package com.yipao.wx.web;

import com.github.pagehelper.PageInfo;
import com.yipao.core.system.SystemConfig;
import com.yipao.core.util.ResponseUtil;
import com.yipao.core.validator.Order;
import com.yipao.core.validator.Sort;
import com.yipao.db.domain.YipaoFootprint;
import com.yipao.db.domain.YipaoSearchHistory;
import com.yipao.db.domain.goods.Brand;
import com.yipao.db.domain.goods.Category;
import com.yipao.db.domain.goods.Goods;
import com.yipao.db.service.*;
import com.yipao.db.service.goods.*;
import com.yipao.db.service.user.UserService;
import com.yipao.wx.annotation.LoginUser;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.validation.constraints.NotNull;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;

/**
 * 商品服务
 *
 * @author tianhao
 */
@RestController
@RequestMapping("/wx/goods")
@Validated
@Slf4j
public class WxGoodsController {

    @Autowired
    private GoodsService goodsService;

    @Autowired
    private GoodsProductService productService;

    @Autowired
    private YipaoIssueService goodsIssueService;

    @Autowired
    private GoodsAttributeService goodsAttributeService;

    @Resource
    private GoodsFormulaService goodsFormulaService;

    @Autowired
    private YipaoBrandService brandService;

    @Autowired
    private YipaoCommentService commentService;

    @Autowired
    private UserService userService;

    @Autowired
    private YipaoCollectService collectService;

    @Autowired
    private YipaoFootprintService footprintService;

    @Autowired
    private CategoryService categoryService;

    @Autowired
    private YipaoSearchHistoryService searchHistoryService;

    @Autowired
    private GoodsSpecificationService goodsSpecificationService;

    @Autowired
    private YipaoGrouponRulesService rulesService;

    private final static ArrayBlockingQueue<Runnable> WORK_QUEUE = new ArrayBlockingQueue<>(9);

    private final static RejectedExecutionHandler HANDLER = new ThreadPoolExecutor.CallerRunsPolicy();

    private static ThreadPoolExecutor executorService = new ThreadPoolExecutor(16, 16, 1000, TimeUnit.MILLISECONDS, WORK_QUEUE, HANDLER);

    /**
     * 商品详情
     * <p>
     * 用户可以不登录。
     * 如果用户登录，则记录用户足迹以及返回用户收藏信息。
     *
     * @param userId 用户ID
     * @param id     商品ID
     * @return 商品详情
     */
    @GetMapping("detail")
    public Object detail(@LoginUser Integer userId, @NotNull Integer id) {
        // 商品信息
        Goods info = goodsService.findById(id);

        // 商品属性
        Callable<List> goodsAttributeListCallable = () -> goodsAttributeService.queryByGid(id);
        // 商品的配方属性
        Callable<Map> goodsFormulaCallable = () -> goodsFormulaService.queryGoodsFormulaByGoodsId(info.getFormulaId()).getAttr();

        // 商品规格 返回的是定制的GoodsSpecificationVo
        Callable<Object> objectCallable = () -> goodsSpecificationService.getSpecificationVoList(id);

        // 商品规格对应的数量和价格
        Callable<List> productListCallable = () -> productService.queryByGid(id);

        // 商品问题，这里是一些通用问题
        Callable<List> issueCallable = () -> goodsIssueService.querySelective("", 1, 4, "", "");

        // 商品品牌商
        Callable<Brand> brandCallable = () -> {
            Integer brandId = info.getBrandId();
            Brand brand;
            if (brandId == 0) {
                brand = new Brand();
            } else {
                brand = brandService.findById(info.getBrandId());
            }
            return brand;
        };


        // 团购信息
        /// Callable<List> grouponRulesCallable = () -> rulesService.queryByGoodsId(id);

        // 用户收藏
        int userHasCollect = 0;
        if (userId != null) {
            userHasCollect = collectService.count(userId, id);
        }

        // 记录用户的足迹 异步处理
        if (userId != null) {
            executorService.execute(() -> {
                YipaoFootprint footprint = new YipaoFootprint();
                footprint.setUserId(userId);
                footprint.setGoodsId(id);
                footprintService.add(footprint);
            });
        }
        FutureTask<List> goodsAttributeListTask = new FutureTask<>(goodsAttributeListCallable);
        FutureTask<Map> goodsFormulaListTask = new FutureTask<>(goodsFormulaCallable);
        FutureTask<Object> objectCallableTask = new FutureTask<>(objectCallable);
        FutureTask<List> productListCallableTask = new FutureTask<>(productListCallable);
        FutureTask<List> issueCallableTask = new FutureTask<>(issueCallable);
        // FutureTask<Map> commentsCallableTsk = new FutureTask<>(commentsCallable);
        FutureTask<Brand> brandCallableTask = new FutureTask<>(brandCallable);
        /// FutureTask<List> grouponRulesCallableTask = new FutureTask<>(grouponRulesCallable);

        executorService.submit(goodsAttributeListTask);
        executorService.submit(goodsFormulaListTask);
        executorService.submit(objectCallableTask);
        executorService.submit(productListCallableTask);
        executorService.submit(issueCallableTask);
        /// executorService.submit(commentsCallableTsk);
        executorService.submit(brandCallableTask);
        /// executorService.submit(grouponRulesCallableTask);

        Map<String, Object> data = new HashMap<>();

        try {
            data.put("info", info);
            data.put("userHasCollect", userHasCollect);
            data.put("issue", issueCallableTask.get());
            /// data.put("comment", commentsCallableTsk.get());
            data.put("specificationList", objectCallableTask.get());
            data.put("productList", productListCallableTask.get());
            // 商品属性
            data.put("attribute", goodsAttributeListTask.get());
            // 商品配方属性
            data.put("formula", goodsFormulaListTask.get());
            data.put("brand", brandCallableTask.get());
            /// data.put("groupon", grouponRulesCallableTask.get());
            //SystemConfig.isAutoCreateShareImage()
            data.put("share", SystemConfig.isAutoCreateShareImage());

        } catch (Exception e) {
            log.error("查询商品详情异常", e);
        }

        // 商品分享图片地址
        data.put("shareImage", info.getShareUrl());
        return ResponseUtil.ok(data);
    }

    /**
     * 商品分类类目
     *
     * @param id 分类类目ID
     * @return 商品分类类目
     */
    @GetMapping("category")
    public Object category(@NotNull Integer id) {
        Category cur = categoryService.findById(id);
        Category parent;
        List<Category> children;

        if (cur.getPid() == 0) {
            parent = cur;
            children = categoryService.queryByPid(cur.getId());
            cur = children.size() > 0 ? children.get(0) : cur;
        } else {
            parent = categoryService.findById(cur.getPid());
            children = categoryService.queryByPid(cur.getPid());
        }
        Map<String, Object> data = new HashMap<>();
        data.put("currentCategory", cur);
        data.put("parentCategory", parent);
        data.put("brotherCategory", children);
        return ResponseUtil.ok(data);
    }

    /**
     * 根据条件搜素商品
     * <p>
     * 1. 这里的前五个参数都是可选的，甚至都是空
     * 2. 用户是可选登录，如果登录，则记录用户的搜索关键字
     *
     * @param devId      设备id
     * @param categoryId 分类类目ID，可选
     * @param keyword    关键字，可选
     * @param userId     用户ID
     * @param page       分页页数
     * @param limit      分页大小
     * @param sort       排序方式，支持"add_time", "retail_price"或"name"
     * @param order      排序类型，顺序或者降序
     * @return 根据条件搜素的商品详情
     */
    @GetMapping("list")
    public Object list(
            Integer devId,
            Integer categoryId,
            String keyword,
            @LoginUser Integer userId,
            @RequestParam(defaultValue = "1") Integer page,
            @RequestParam(defaultValue = "10") Integer limit,
            @Sort(accepts = {"add_time", "retail_price", "name"}) @RequestParam(defaultValue = "add_time") String sort,
            @Order @RequestParam(defaultValue = "desc") String order) {

        // 添加到搜索历史
        if (userId != null && StringUtils.isNotBlank(keyword)) {
            YipaoSearchHistory searchHistoryVo = new YipaoSearchHistory();
            searchHistoryVo.setKeyword(keyword);
            searchHistoryVo.setUserId(userId);
            searchHistoryVo.setFrom("wx");
            searchHistoryService.save(searchHistoryVo);
        }

        // 查询列表数据
        List<Goods> goodsList;
        if (devId == null) {
            goodsList = goodsService.querySelective(categoryId, keyword, page, limit, sort, order);
        } else {
            // 查询指定设备下的商品列表
            goodsList = goodsService.querySelectiveByDevId(devId, categoryId, keyword, page, limit, sort, order);
        }
        PageInfo<Goods> pagedList = PageInfo.of(goodsList);

        Map<String, Object> entity = new HashMap<>(6);
        entity.put("list", goodsList);
        entity.put("total", pagedList.getTotal());
        entity.put("page", pagedList.getPageNum());
        entity.put("limit", pagedList.getPageSize());
        entity.put("pages", pagedList.getPages());

        // 因为这里需要返回额外的filterCategoryList参数，因此不能方便使用ResponseUtil.okList
        return ResponseUtil.ok(entity);
    }

    /**
     * 商品详情页面“大家都在看”推荐商品
     *
     * @param id, 商品ID
     * @return 商品详情页面推荐商品
     */
    @GetMapping("related")
    public Object related(@NotNull Integer id) {
        Goods goods = goodsService.findById(id);
        if (goods == null) {
            return ResponseUtil.badArgumentValue();
        }

        // 目前的商品推荐算法仅仅是推荐同类目的其他商品
        int cid = goods.getCategoryId();

        // 查找六个相关商品
        int related = 6;
        List<Goods> goodsList = goodsService.queryByCategory(cid, 0, related);
        return ResponseUtil.okList(goodsList);
    }

    /**
     * 在售的商品总数
     *
     * @return 在售的商品总数
     */
    @GetMapping("count")
    public Object count() {
        Integer goodsCount = goodsService.queryOnSale();
        return ResponseUtil.ok(goodsCount);
    }

}
